﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.LanguageService.Syntax;

public sealed class SyntaxToken : AbstractTextNode
{
    internal SyntaxToken(SyntaxKinds kind) : base(kind, null)
    {
    }


    public static SyntaxToken Default { get; } = new(SyntaxKinds.Unknown);

    /// <summary>
    ///     如果此Token前有换行，返回<see langword="true" />。
    /// </summary>
    public bool HasPrecedingLinebreak => GetFlags(SyntaxNodeFlags.PrecedingLinebreak);


    /// <summary>
    ///     如果此Token后后换行，返回<see langword="true" />。
    /// </summary>
    public bool HasTrailingLinebreak => GetFlags(SyntaxNodeFlags.TrailingLinebreak);


    public static bool IsNullOrEmpty([NotNullWhen(false)] SyntaxToken? token)
    {
        return token == null ||
               ReferenceEquals(token, Default) ||
               token.IsEmpty;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        if (visitor.IsFinished)
        {
            return;
        }

        if (this is T target && visitor.Predicate(target))
        {
            visitor.Finish(this);
        }

        base.AcceptVisitor(visitor);
    }
}


public static partial class NodeFactory
{
    public static SyntaxToken CreateSyntaxToken(SyntaxKinds kind)
    {
        Debug.Assert(SyntaxFacts.IsToken(kind));
        return new SyntaxToken(kind);
    }


    public static SyntaxToken CreateSyntaxToken(SourceNode source)
    {
        Debug.Assert(SyntaxFacts.IsToken(source.Kind));
        SyntaxToken token = new(source.Kind);
        token.UpdateFrom(source);
        return token;
    }
}


public static partial class NodeConverter
{
    public static StringLiteral ToString(ITextNode token)
    {
        StringLiteral str = NodeFactory.CreateStringLiteral(null, false, token.Text);
        str.UpdateFrom(token);
        return str;
    }


    public static Identifier ToIdentifier(SyntaxToken token)
    {
        Identifier id = NodeFactory.CreateIdentifier();
        id.UpdateFrom(token);

        if (!StringHelper.IsValidIdentifier(token.Text))
        {
            id.SetFlags(SyntaxNodeFlags.InvalidIdentifier);
        }

        return id;
    }
}